<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- 
        实现iterable接口要具备支持迭代的自我识别能力和创建实现iterator接口的对象能力
        这意味着必须暴露一个以Symbol.Iterator为键的属性，这个属性引用一个迭代器工厂函数，工厂函数返回一个迭代器对象
     -->
    <script>
        // 检查是否存在默认迭代器属性可以暴露这个工厂函数
        let num = 1
        let obj = {}
        // 这两类型没有实现迭代器工厂函数
        console.log(num[Symbol.iterator]) // undefined
        console.log(obj[Symbol.iterator]) // undefined

        let str = '123'
        let arr = [1, 2, 3]
        let map = new Map().set('a', 1).set('b', 2)
        let set = new Set().add(1).add(2)
        let els = document.querySelectorAll('div')
        // 这些类型都实现了迭代器工厂函数
        console.log(str[Symbol.iterator]) // ƒ values() { [native code] }
        console.log(arr[Symbol.iterator]) // ƒ values() { [native code] }
        console.log(map[Symbol.iterator]) // ƒ values() { [native code] }
        console.log(set[Symbol.iterator]) // ƒ values() { [native code] }
        console.log(els[Symbol.iterator]) // ƒ values() { [native code] }
        // 调用这个工厂函数会返回一个迭代器
        console.log(str[Symbol.iterator]()) // 迭代器
        console.log(arr[Symbol.iterator]()) // 迭代器
        console.log(map[Symbol.iterator]()) // 迭代器
        console.log(set[Symbol.iterator]()) // 迭代器
        console.log(els[Symbol.iterator]()) // 迭代器

        /*
            可迭代对象不需要显示的调用这个工厂函数。
            语言特性包括
            for of、数组结构、扩展操作符、Array.from()、创建集合、创建映射、Promise.all()、Promise.race()、yield*操作符,在生成器中使用
        */

        // for of循环
        for (let el of arr) {
            console.log(el) // 1 2 3
        }
        
        // 数组结构
        let [a,b] = arr
        console.log(a,b)  // 1 2

        // 扩展操作符
        let arr1 = [...arr]
        console.log(arr1) // [1,2,3]

        // Array.from()
        let arr2 = Array.from(arr)
        console.log(arr2) // [1,2,3]

        // Set构造函数
        let set1 = new Set(arr)
        console.log(set1) // {1,2,3}

        // Map构造函数
        let pairs = arr.map((x, i) => [x, i])
        console.log(pairs) // [[1,0], [2,1], [3,2]]
        let map1 = new Map(pairs)
        console.log(map1)  // Map(3) {1 => 0, 2 => 1, 3 => 2}

        /*
          如果对象原型链上的父类实现了interable接口，那对象也就实现了这个接口
        */
       class FooArray extends Array {}
       let fooArray = new FooArray(1,2,3,4)
       for (el of fooArray) {
        console.log(el) // 1 2 3 4
       }
    </script>
</body>

</html>